Skip to content

Adopt @jssg/utils import helpers across React JSSG codemods - #15

Merged
alexbit-codemod merged 10 commits into
mainfrom
cursor/leverage-jssg-utils-0824
Oct 31, 2026
Merged

alexbit-codemod merged 10 commits into
mainfrom
cursor/leverage-jssg-utils-0824

Conversation

@alexbit-codemod

@alexbit-codemod alexbit-codemod commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Makes React JSSG codemods use @jssg/utils for import detection and rewriting instead of ad-hoc scanners, and bumps @jssg/utils to ^0.0.10.

Package and codemod.yaml versions are bumped (patch) for every touched codemod.

Test runner / TypeScript

  • Why not pnpm dlx? Concurrent pnpm -r test raced on the shared dlx cache (ENOENT unlink under ~/.cache/pnpm/dlx). Fix: declare codemod@1.18.6 as a real devDependency and invoke codemod on PATH — no custom wrapper.
  • TypeScript 7: bump to ^7.0.2 for tsc. TS 7’s main export no longer has the classic compiler API, so prop-types-typescript parity tests use @typescript/typescript6 only for createSourceFile / parse checks.

New fixtures

CJS, aliases, quote/merge style, multiline import cleanup, and related utils edge cases across the React codemod packages (see diff). prop-types-typescript coverage is in parity-cases.mjs; update-react-imports adds utils-focused tests/ cases.

Codex review follow-up

Codemod-side regressions from the review are fixed, each with a fixture: namespace fallback in fragment-ref-wrappers, multi-binding cleanup in prop-types-typescript, alias reuse in react-proptypes-to-prop-types, namespace cleanup crash in use-browser, mixed aliases in use-context-hook, multiple React aliases in create-element-to-jsx / find-dom-node / pure-render-mixin / sort-comp, CommonJS output in remove-legacy-context, and duplicate-export collisions in unprefix-stable-apis.

Known @jssg/utils gaps (follow-up in codemod/codemod, not worked around here)

  • getAllImports({ type: "default" }) drops namespace imports whenever a default import exists.
  • addImport (named) checks existence by exported name only, ignoring aliases, and treats the namespace fallback as an existing binding.
  • addImport insertion point includes require() declarations nested inside functions.
  • removeImport always edits the first matching statement; it can't target a specific alias/binding.
  • updateImport only edits the first matching clause and keys renames by exported name.
  • No import type awareness: type-only bindings are returned as values, and runtime specifiers get merged into type-only imports.

Test plan

  • pnpm run ci (all package tests + check-types on TypeScript 7)
  • CI green
Open in Web Open in Cursor 

cursoragent and others added 7 commits October 30, 2026 21:22
Use getImport/getAllImports, addImport, and updateImport from
@jssg/utils@^0.0.10 in use-context-hook, react-dom-to-react-dom-factories,
unprefix-stable-apis, and fragment-ref-wrappers. Add fixtures that fail
under ad-hoc import handling (CJS named useContext, aliased DOM/React,
type-only unprefix, single-quote Fragment merge).

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Refactor replace-act-import, replace-use-form-state, replace-reactdom-render,
and prop-types-typescript to rely on getImport/getAllImports/addImport/
removeImport instead of ad-hoc import rewriting, and add fixtures that fail
under quote-blind or line-regex handling but pass with utils.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Use getImport/getAllImports/addImport/removeImport for memoization cleanup,
createFactory removal, PropTypes migration, and React alias resolution in
find-dom-node/create-element-to-jsx/pure-render-mixin. Partial utils adoption
in update-react-imports preserves its destructure/namespace policy. Add
fixtures covering no-semicolon siblings, named import cleanup, double-quote
prop-types insertion, and aliased namespace React bindings.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Wire getImport/getAllImports/addImport/removeImport/updateImport into
use-browser, remove-legacy-context, pure-component, react-native-view-prop-types,
react-to-react-dom (partial), and sort-comp. Bump leftover @jssg/utils ^0.0.2
deps to ^0.0.10 and guard remove-forward-ref/replace-string-ref against
getImport namespace fallbacks. Add fixtures for single-quote merge, CJS React,
aliased View/findDOMNode, multi-specifier cleanup, and aliased React namespace
sort-comp.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Bump changeset packages (0.1.2→0.1.3, react-19-3 0.1.1→0.1.2) and sync
codemod.yaml. Add update-react-imports fixtures for single-quote removeImport
and no-semicolon destructure, plus a CJS require parity case for
prop-types-typescript.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
Parallel `pnpm -r test` raced on the shared pnpm dlx cache
(ENOENT unlink under ~/.cache/pnpm/dlx). Install codemod@1.18.6 at
the workspace root and run tests through scripts/run-codemod.mjs so
packages keep their cwd without concurrent dlx installs.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
@alexbit-codemod

Copy link
Copy Markdown
Contributor Author

/codex-review

cursoragent and others added 2 commits October 30, 2026 21:57
`typescript@latest` resolved to 7.0.2, whose package entry only exports
version metadata. That made `ts.ScriptTarget` undefined in
prop-types-typescript parity tests on CI. Pin ~5.9.3 via package
ranges and a pnpm override.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
pnpm dlx was fine conceptually — the CI failure was a parallel-cache race
when many packages ran `pnpm dlx` at once. Prefer declaring `codemod` as a
devDependency and invoking it on PATH.

Also upgrade typescript to ^7.0.2. TS 7 dropped the classic compiler API
from the main export, so prop-types-typescript parity tests import
createSourceFile via @typescript/typescript6.

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
@alexbit-codemod

Copy link
Copy Markdown
Contributor Author

/codex-review

@cursor

cursor Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

/codex-review

2 similar comments
@alexbit-codemod

Copy link
Copy Markdown
Contributor Author

/codex-review

@alexbit-codemod

Copy link
Copy Markdown
Contributor Author

/codex-review

@github-actions

Copy link
Copy Markdown
Contributor

Codex Review

Reviewed all 210 changed files. Existing tests and type checks pass, but comparisons against the base confirm several correctness regressions and gaps in alias, namespace, and import-cleanup coverage.

Findings

  • [HIGH] codemods/fragment-ref-wrappers/scripts/codemod.ts:168 Reject namespace fallbacks as named Fragment bindings
  • [HIGH] codemods/prop-types-typescript/scripts/codemod.ts:962 Retain PropTypes imports with remaining references
  • [HIGH] codemods/react-proptypes-to-prop-types/scripts/codemod.ts:144 Reuse the existing PropTypes alias
  • [HIGH] codemods/remove-memoization/scripts/codemod.ts:305 Remove the specific unused import binding
  • [HIGH] codemods/replace-act-import/scripts/codemod.ts:163 Ensure migrated calls retain their local bindings
  • [HIGH] codemods/replace-reactdom-render/scripts/codemod.ts:307 Keep generated imports at module scope
  • [HIGH] codemods/unprefix-stable-apis/scripts/codemod.ts:134 Preserve collision decisions for each aliased binding
  • [HIGH] codemods/use-browser/scripts/codemod.ts:500 Keep runtime bindings out of type-only imports
  • [HIGH] codemods/use-browser/scripts/codemod.ts:524 Stop hook cleanup before namespace fallback
  • [HIGH] codemods/use-context-hook/scripts/codemod.ts:176 Limit useContext import renames to active bindings
  • [MEDIUM] codemods/create-element-to-jsx/scripts/codemod.ts:45 Resolve every relevant React alias
  • [MEDIUM] codemods/react-dom-to-react-dom-factories/scripts/codemod.ts:234 Update every DOM import clause
  • [MEDIUM] codemods/remove-legacy-context/scripts/codemod.ts:310 Preserve CommonJS syntax for new React helpers
  • [MEDIUM] codemods/use-context-hook/scripts/codemod.ts:18 Recover namespace bindings alongside default imports

- fragment-ref-wrappers: don't treat a namespace fallback as a named Fragment binding
- prop-types-typescript: collect every default binding; keep imports still referenced (incl. type refs)
- react-proptypes-to-prop-types: reuse the existing prop-types alias (import, namespace, require)
- use-browser: stop hook cleanup before removeImport falls back to a namespace import
- use-context-hook: rename every useContext reference when its import is renamed
- create-element-to-jsx, find-dom-node, pure-render-mixin, sort-comp: match against all React aliases
- remove-legacy-context: generate a CommonJS React binding for CommonJS sources
- unprefix-stable-apis: use one collision-safe rename plan per exported name

Co-authored-by: Alex Bit <alexbit-codemod@users.noreply.github.com>
@alexbit-codemod
alexbit-codemod merged commit 6b48969 into main Oct 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants